// File: PathSimulation.fx

Texture2D txDiffuse : register( t0 );
Texture2D txShadow1 : register( t1 );
Texture2D txShadow2 : register( t2 );
Texture2D txNormal : register( t3 );

SamplerState samLinear : register( s0 );
SamplerState samClamp : register( s1 );

cbuffer cbView : register( b0 )
{
	matrix View;
};

cbuffer cbProjection: register( b1 )
{
	matrix Projection;
};

cbuffer cbModel : register( b2 )
{
	matrix World;
	float4 vMeshColor;
};

cbuffer cbLight1 : register( b3 )
{
	float4 vDiffuseColor1;
	float4 vAmbientColor1;
	float4 LightPos1;
	matrix LightView1;
	matrix LightProjection1;
}

cbuffer cbLight2 : register( b4 )
{
	float4 vDiffuseColor2;
	float4 vAmbientColor2;
	float4 LightPos2;
	matrix LightView2;
	matrix LightProjection2;
}

cbuffer cbOptions : register( b5 )
{
	float bumpiness;
}

//--------------------------------------------------------------------------------------
struct VS_INPUT
{
	float4 Pos : POSITION;
	float2 Tex : TEXCOORD0;
	float3 Normal : NORMAL;
	float3 Tangent : TANGENT;
	float3 Binormal : BINORMAL;
	float3 Color : COLOR;
};

struct PS_INPUT
{
	float4 Pos : SV_POSITION;
	float2 Tex : TEXCOORD0;
	float3 Normal : NORMAL;
	float4 LightVector1 : LIGHTVECTOR1;
	float4 ShadowMapPos1 : TEXCOORD1;
	float4 LightVector2 : LIGHTVECTOR2;
	float4 ShadowMapPos2 : TEXCOORD2;
	float3 Binormal : BINORMAL;
	float3 Tangent : TANGENT;
	nointerpolation float3 Color : COLOR;
};

// Vertex Shader
PS_INPUT VS( VS_INPUT input )
{
	PS_INPUT output = (PS_INPUT)0;
	input.Pos.w = 1.0f;
	output.Pos = mul( input.Pos, World );
	output.Pos = mul( output.Pos, View );
	output.Pos = mul( output.Pos, Projection );
	output.ShadowMapPos1 = mul( input.Pos, World );
	output.ShadowMapPos1 = mul( output.ShadowMapPos1, LightView1);
	output.ShadowMapPos1 = mul( output.ShadowMapPos1, LightProjection1);
	output.ShadowMapPos2 = mul( input.Pos, World );
	output.ShadowMapPos2 = mul( output.ShadowMapPos2, LightView2);
	output.ShadowMapPos2 = mul( output.ShadowMapPos2, LightProjection2);
	output.Normal = input.Normal;
	output.Normal = mul(output.Normal, (float3x3)World);
	output.LightVector1 = LightPos1 - input.Pos;
	output.LightVector2 = LightPos2 - input.Pos;
	output.Tex = input.Tex;
	output.Binormal = input.Binormal;
	output.Binormal = mul(output.Binormal, (float3x3)World);
	output.Tangent = input.Tangent;
	output.Tangent = mul(output.Tangent, (float3x3)World);
	output.Color = input.Color;
	return output;
}

// Pixel Shader
float4 PS( PS_INPUT input) : SV_Target
{
	float4 vColor;
	float casterDepth;
	float inputDepth;
	float idiff;
	float2 shadowMapUV;
	float3 normalMapNormal;
	float3 normalMapTangentSpace;

	input.Normal = normalize(input.Normal);
	normalMapNormal = txNormal.Sample( samLinear, input.Tex );
	normalMapNormal = (normalMapNormal * 2.f) - 1.f;
	normalMapNormal = normalize(normalMapNormal);
	normalMapNormal *= bumpiness;
	input.Normal = float3( 0.0f, 1.0f, 0.0f );
	input.Normal = normalize(input.Normal + normalMapNormal.x * input.Tangent + normalMapNormal.y * input.Binormal);

	input.LightVector1 = normalize(input.LightVector1);
	input.LightVector2 = normalize(input.LightVector2);
	vColor = vAmbientColor1 + vAmbientColor2;
	shadowMapUV.x = input.ShadowMapPos1.x / input.ShadowMapPos1.w / 2.f + 0.5f;//unit cube 3d cartesian to uv 2d texture coordinates
	shadowMapUV.y = - input.ShadowMapPos1.y / input.ShadowMapPos1.w / 2.f + 0.5f;
	if((saturate(shadowMapUV.x) == shadowMapUV.x) && (saturate(shadowMapUV.y) == shadowMapUV.y))//Pixel is in shadow map's range
	{
		casterDepth = txShadow1.Sample(samClamp, shadowMapUV).r;
		inputDepth = (1 - input.ShadowMapPos1.z / input.ShadowMapPos1.w) + 0.0001f;//bias
		if(inputDepth > casterDepth)//input is caster
		{
			idiff = saturate(dot(input.Normal, input.LightVector1));
			vColor += idiff * vDiffuseColor1;
		}
	}
	shadowMapUV.x = input.ShadowMapPos2.x / input.ShadowMapPos2.w / 2.f + 0.5f;//unit cube 3d cartesian to uv 2d texture coordinates
	shadowMapUV.y = - input.ShadowMapPos2.y / input.ShadowMapPos2.w / 2.f + 0.5f;
	if((saturate(shadowMapUV.x) == shadowMapUV.x) && (saturate(shadowMapUV.y) == shadowMapUV.y))//Pixel is in shadow map's range
	{
		casterDepth = txShadow2.Sample(samClamp, shadowMapUV).r;
		inputDepth = (1 - input.ShadowMapPos2.z / input.ShadowMapPos2.w) + 0.0001f;//bias
		if(inputDepth > casterDepth)//input is caster
		{
			idiff = saturate(dot(input.Normal, input.LightVector2));
			vColor += idiff * vDiffuseColor2;
		}
	}
	float4 ambientColor = {input.Color.r, input.Color.g, input.Color.b, 0};
		return txDiffuse.Sample( samLinear, input.Tex ) * vMeshColor * ( vColor ) + ambientColor;
}